package logger

import (
	"os"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

type Config struct {
	LogFile       string
	SyncWriteFile bool
	Fields        []zap.Field
}

var (
	_zap, _ = zap.NewDevelopment()
	logger  = _zap.Sugar()
	Debug   = logger.Debug
	Debugf  = logger.Debugf
	Debugw  = logger.Debugw
	Info    = logger.Info
	Infof   = logger.Infof
	Infow   = logger.Infow
	Warn    = logger.Warn
	Warnf   = logger.Warnf
	Warnw   = logger.Warnw
	Error   = logger.Error
	Errorf  = logger.Errorf
	Errorw  = logger.Errorw
	DPanic  = logger.DPanic
	DPanicf = logger.DPanicf
	DPanicw = logger.DPanicw
	Panic   = logger.Panic
	Panicf  = logger.Panicf
	Panicw  = logger.Panicw
	Fatal   = logger.Fatal
	Fatalf  = logger.Fatalf
	Fatalw  = logger.Fatalw
)

func Global(sugaredLogger *zap.SugaredLogger) {
	logger = sugaredLogger
	Debug = sugaredLogger.Debug
	Debugf = sugaredLogger.Debugf
	Debugw = sugaredLogger.Debugw
	Info = sugaredLogger.Info
	Infof = sugaredLogger.Infof
	Infow = sugaredLogger.Infow
	Warn = sugaredLogger.Warn
	Warnf = sugaredLogger.Warnf
	Warnw = sugaredLogger.Warnw
	Error = sugaredLogger.Error
	Errorf = sugaredLogger.Errorf
	Errorw = sugaredLogger.Errorw
	DPanic = sugaredLogger.DPanic
	DPanicf = sugaredLogger.DPanicf
	DPanicw = sugaredLogger.DPanicw
	Panic = sugaredLogger.Panic
	Panicf = sugaredLogger.Panicf
	Panicw = sugaredLogger.Panicw
	Fatal = sugaredLogger.Fatal
	Fatalf = sugaredLogger.Fatalf
	Fatalw = sugaredLogger.Fatalw
}

func NewZap(config Config) *zap.SugaredLogger {
	var multiCore []zapcore.Core
	encoder := zapcore.NewJSONEncoder(zapcore.EncoderConfig{
		MessageKey:  "message",
		LevelKey:    "level",
		EncodeLevel: zapcore.CapitalLevelEncoder,
		TimeKey:     "time",
		EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendString(t.Format("2006-01-02 15:04:05"))
		},
		StacktraceKey: "stacktrace",
		CallerKey:     "caller",
		EncodeCaller:  zapcore.FullCallerEncoder,
		EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendInt64(int64(d) / 1000000)
		},
	})

	multiCore = append(multiCore, zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.DebugLevel))
	if config.SyncWriteFile && len(config.LogFile) > 0 {
		fileWriter := &lumberjack.Logger{
			Filename:   config.LogFile,
			MaxSize:    300, // 日志文件的最大大小（以MB为单位）
			MaxBackups: 3,   // 保留旧文件的最大个数
			MaxAge:     7,   // 保留旧文件的最大天数
			Compress:   true,
			LocalTime:  true,
		}
		multiCore = append(multiCore, zapcore.NewCore(encoder, zapcore.AddSync(fileWriter), zapcore.DebugLevel))
	}

	core := zapcore.NewTee(multiCore...)
	options := []zap.Option{zap.AddCaller(), zap.AddStacktrace(zap.WarnLevel)}
	if len(config.Fields) > 0 {
		options = append(options, zap.Fields(config.Fields...))
	}

	zapLog := zap.New(core, options...)
	return zapLog.Sugar()
}

func Sync() error {
	return logger.Sync()
}

func Logger() *zap.Logger {
	return logger.Desugar()
}

func SugaredLogger() *zap.SugaredLogger {
	return logger
}
